use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all(serialize = "PascalCase", deserialize = "PascalCase"))]
pub struct Config {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub interface: Option<InterfaceConfig>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub peers: Vec<PeerConfig>,
}

impl Config {
    pub fn to_config_string(&self) -> String {
        let mut arr: Vec<String> = Vec::new();

        if let Some(interface) = self.interface.as_ref() {
            arr.push("[Interface]".to_string());
            arr.push(interface.to_config_string())
        }

        if !self.peers.is_empty() {
            for peer in self.peers.iter() {
                arr.push("[Peer]".to_string());
                arr.push(peer.to_config_string())
            }
        }
        arr.join("\n")
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all(serialize = "PascalCase", deserialize = "PascalCase"))]
pub struct InterfaceConfig {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub private_key: Option<String>,
}

impl InterfaceConfig {
    pub fn to_config_string(&self) -> String {
        let mut arr: Vec<String> = Vec::new();

        if let Some(private_key) = self.private_key.as_ref() {
            arr.push(format!("PrivateKey = {}", private_key));
        }

        arr.join("\n")
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all(serialize = "PascalCase", deserialize = "PascalCase"))]
pub struct PeerConfig {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub public_key: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub endpoint: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub persistent_keepalive: Option<u32>,
    #[serde(rename = "AllowedIPs", skip_serializing_if = "Vec::is_empty")]
    pub allowed_ips: Vec<cidr::IpInet>,
}

impl PeerConfig {
    pub fn to_config_string(&self) -> String {
        let mut arr: Vec<String> = Vec::new();

        if let Some(public_key) = self.public_key.as_ref() {
            arr.push(format!("PublicKey = {}", public_key));
        }

        if let Some(endpoint) = self.endpoint.as_ref() {
            arr.push(format!("Endpoint = {}", endpoint));
        }

        if let Some(persistent_keepalive) = self.persistent_keepalive {
            arr.push(format!("PersistentKeepalive = {}", persistent_keepalive));
        }

        if !self.allowed_ips.is_empty() {
            let allowed_ips = self
                .allowed_ips
                .iter()
                .map(|allowed_ip| allowed_ip.to_string())
                .collect::<Vec<_>>()
                .join(", ");

            arr.push(format!("AllowedIPs = {}", allowed_ips));
        }
        arr.join("\n")
    }
}
